package com.bee.beemanage.system.configs;

import com.bee.beemanage.system.configs.SecurityConfigs.AccessHandler;
import com.bee.beemanage.system.configs.SecurityConfigs.PermitAllUrlProperties;
import com.bee.beemanage.system.configs.SecurityConfigs.UserDetailsServiceImpl;
import com.bee.beemanage.system.aspect.filters.TokenFilter;
import com.bee.beemanage.system.aspect.filters.VerifyCodeFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;

import javax.annotation.Resource;

/**
 * @author 陈国松
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {


    @Resource
    private PermitAllUrlProperties permitAllUrlProperties;
    @Resource
    private AuthenticationEntryPoint userNotLoginHandler;
    @Resource
    private AuthenticationSuccessHandler authenticationSuccessHandler;
    @Resource
    private AuthenticationFailureHandler authenticationFailureHandler;
    @Resource
    private AccessHandler accessHandler;
    @Resource
    private TokenFilter tokenFilter;

    @Resource
    private VerifyCodeFilter verifyCodeFilter;
    @Resource
    private LogoutSuccessHandler logoutSuccessHandler;

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and().csrf().disable();
        http.authorizeRequests()
                // 放行接口
                .antMatchers(permitAllUrlProperties.getIgnoreUrls().toArray(new String[0])).permitAll()
                // 除上面外的所有请求全部需要鉴权认证
                .anyRequest().authenticated()
                //异常处理(权限拒绝、登录失效等)
                .and().exceptionHandling()
                //匿名用户访问无权限资源时的异常处理
                .authenticationEntryPoint(userNotLoginHandler)
                //自定义403
                .accessDeniedHandler(accessHandler)
                //允许所有用户登入
                .and().formLogin().permitAll()
                    //登录成功处理逻辑
                    .successHandler(authenticationSuccessHandler)
                    //登录失败处理逻辑
                    .failureHandler(authenticationFailureHandler)
                //允许所有用户登入登出
                .and().logout().permitAll()
                .logoutSuccessHandler(logoutSuccessHandler)
                //会话管理
                .and().sessionManagement()
                    //禁用session
                    .sessionCreationPolicy(SessionCreationPolicy.NEVER);
        //token过滤器放置在用户名密码登录方式之前
        http.addFilterBefore(tokenFilter,UsernamePasswordAuthenticationFilter.class);
        //验证码过滤器
        http.addFilterBefore(verifyCodeFilter,TokenFilter.class);
    }

    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        // 设置默认的加密方式（强hash方式加密）
        return new BCryptPasswordEncoder();
    }

    @Bean
    @Override
    public UserDetailsService userDetailsService() {
        //获取用户账号密码及权限信息
        return new UserDetailsServiceImpl();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //配置认证方式
        auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());
    }

}
